import pandas as pd
import numpy as np
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from collections import defaultdict
import warnings

warnings.filterwarnings('ignore')


class ExamScheduler:
    def __init__(self):
        self.classrooms = None
        self.time_slots = None
        self.students = None
        self.schedule_result = None

    def load_data(self, classroom_file, timeslot_file, student_file):
        """加载三个数据文件"""
        try:
            # 加载考场信息
            self.classrooms = pd.read_excel(classroom_file)
            print(f"加载考场信息: {len(self.classrooms)} 个考场")

            # 加载时间单元
            self.time_slots = pd.read_excel(timeslot_file)
            print(f"加载时间单元: {len(self.time_slots)} 个时间单元")

            # 加载学生数据
            self.students = pd.read_excel(student_file)
            print(f"加载学生数据: {len(self.students)} 条考试记录")

            return True
        except Exception as e:
            print(f"数据加载错误: {e}")
            return False

    def preprocess_data(self):
        """数据预处理"""
        # 处理时间单元数据
        self.time_slots['考试日期'] = self.time_slots['时间单元编号*'].str.split('-').str[0] + '-' + \
                                      self.time_slots['时间单元编号*'].str.split('-').str[1]
        self.time_slots['场次'] = self.time_slots['时间单元编号*'].str.split('-').str[2]
        self.time_slots['时间段'] = self.time_slots['考试开始时间*'].str.split().str[1]

        # 添加时间顺序标识
        time_order = {'08:30:00': 1, '10:30:00': 2, '14:00:00': 3, '16:00:00': 4}
        self.time_slots['时间顺序'] = self.time_slots['时间段'].map(time_order)

        # 按日期和时间排序
        self.time_slots = self.time_slots.sort_values(['考试日期', '时间顺序'])

        # 分析学生考试情况
        self._analyze_student_exams()

        print("数据预处理完成")

    def _analyze_student_exams(self):
        """分析每个学生的考试情况"""
        # 按学生分组，统计每个学生的考试科目
        student_groups = self.students.groupby('考生学号*')

        self.student_exams = {}

        for student_id, group in student_groups:
            exams = group.to_dict('records')
            self.student_exams[student_id] = {
                'name': exams[0]['考生姓名*'],
                'exams': exams,
                'exam_count': len(exams),
                'exam_types': set(exam['开闭卷'] for exam in exams)
            }

        # 统计学生考试数量分布
        exam_count_dist = {}
        for student_id, info in self.student_exams.items():
            count = info['exam_count']
            exam_count_dist[count] = exam_count_dist.get(count, 0) + 1

        print("学生考试数量分布:", exam_count_dist)

        # 分析课程数据
        self.course_groups = self.students.groupby('课程编号*')
        self.course_info = {}

        for course_id, group in self.course_groups:
            self.course_info[course_id] = {
                'name': group.iloc[0]['课程名称*'],
                'exam_type': group.iloc[0]['开闭卷'],
                'student_count': len(group),
                'students': list(group['考生学号*'].unique())
            }

        print(f"课程总数: {len(self.course_info)}")

    def _get_student_schedule_plan(self, exam_count):
        """根据考试数量确定学生的安排计划"""
        if exam_count == 1:
            # 只有一门考试，可以安排在任意场次
            return {'days': 1, 'exams_per_day': [1], 'flexible': True}
        elif exam_count == 2:
            # 考试数量为2，安排在同一个半天
            return {'days': 1, 'exams_per_day': [2], 'require_same_half_day': True}
        elif exam_count <= 4:
            # 考试数量为3或4，安排在同一天
            return {'days': 1, 'exams_per_day': [exam_count], 'require_same_half_day': False}
        else:
            # 考试数量大于4，第一天安排4门，剩余的考试安排在第二天
            first_day = min(4, exam_count)
            second_day = exam_count - first_day
            return {'days': 2, 'exams_per_day': [first_day, second_day], 'require_same_half_day': False}

    def _get_available_time_slots(self, date, exam_count, require_same_half_day=False, flexible=False):
        """获取可用的时间单元组合"""
        date_slots = self.time_slots[self.time_slots['考试日期'] == date]
        if len(date_slots) == 0:
            return []

        # 按时间顺序排序
        date_slots = date_slots.sort_values('时间顺序')

        available_combinations = []

        if flexible:
            # 灵活安排 - 可以安排在任意场次
            if exam_count == 1:
                # 单门考试，每个时间单元都是一个可能的组合
                for _, slot in date_slots.iterrows():
                    available_combinations.append(pd.DataFrame([slot]))
            else:
                # 多门考试，需要连续时间单元
                if len(date_slots) >= exam_count:
                    for i in range(len(date_slots) - exam_count + 1):
                        combination = date_slots.iloc[i:i + exam_count]
                        available_combinations.append(combination)
        elif require_same_half_day:
            # 需要同一个半天
            morning_slots = date_slots[date_slots['时间顺序'].isin([1, 2])]
            afternoon_slots = date_slots[date_slots['时间顺序'].isin([3, 4])]

            # 检查上午是否有足够的连续时间单元
            if len(morning_slots) >= exam_count:
                for i in range(len(morning_slots) - exam_count + 1):
                    combination = morning_slots.iloc[i:i + exam_count]
                    available_combinations.append(combination)

            # 检查下午是否有足够的连续时间单元
            if len(afternoon_slots) >= exam_count:
                for i in range(len(afternoon_slots) - exam_count + 1):
                    combination = afternoon_slots.iloc[i:i + exam_count]
                    available_combinations.append(combination)
        else:
            # 不需要同一个半天，但需要连续时间单元
            if len(date_slots) >= exam_count:
                for i in range(len(date_slots) - exam_count + 1):
                    combination = date_slots.iloc[i:i + exam_count]
                    available_combinations.append(combination)

        return available_combinations

    def _find_available_classroom_for_slot(self, time_slot_id, exam_type, classroom_usage):
        """为时间单元找到可用的考场"""
        available_classrooms = []

        for _, classroom in self.classrooms.iterrows():
            classroom_id = classroom['考场编号']

            # 检查考场容量
            if classroom_usage[time_slot_id][classroom_id] >= classroom['考场容纳人数']:
                continue

            # 检查考场类型 - 确保开卷和闭卷不混用
            if classroom_usage[time_slot_id].get(f"{classroom_id}_type") is not None:
                if classroom_usage[time_slot_id].get(f"{classroom_id}_type") != exam_type:
                    continue

            available_classrooms.append(classroom)

        return available_classrooms

    def _initialize_classroom_usage(self):
        """初始化考场使用情况"""
        classroom_usage = {}

        for _, slot in self.time_slots.iterrows():
            time_slot_id = slot['时间单元编号*']
            classroom_usage[time_slot_id] = {}

            for _, classroom in self.classrooms.iterrows():
                classroom_id = classroom['考场编号']
                classroom_usage[time_slot_id][classroom_id] = 0  # 已安排学生数
                classroom_usage[time_slot_id][f"{classroom_id}_type"] = None  # 考试类型

        return classroom_usage

    def generate_schedule(self):
        """生成考试安排 - 按照新规则"""
        if self.classrooms is None or self.time_slots is None or self.students is None:
            return False

        self.preprocess_data()

        # 获取所有日期
        dates = sorted(self.time_slots['考试日期'].unique())

        # 初始化考场使用情况
        classroom_usage = self._initialize_classroom_usage()

        # 初始化安排结果
        schedule_list = []
        student_schedule = {}  # 记录学生的安排情况

        # 按考试数量排序，先安排考试多的学生
        students_by_exam_count = sorted(
            self.student_exams.items(),
            key=lambda x: x[1]['exam_count'],
            reverse=True
        )

        # 分离开卷和闭卷学生
        open_book_students = []
        closed_book_students = []

        for student_id, info in students_by_exam_count:
            if '开卷' in info['exam_types']:
                open_book_students.append((student_id, info))
            else:
                closed_book_students.append((student_id, info))

        print(f"开卷学生: {len(open_book_students)} 人")
        print(f"闭卷学生: {len(closed_book_students)} 人")

        # 安排开卷学生
        self._schedule_student_group(open_book_students, '开卷', dates, schedule_list, classroom_usage,
                                     student_schedule)

        # 安排闭卷学生
        self._schedule_student_group(closed_book_students, '闭卷', dates, schedule_list, classroom_usage,
                                     student_schedule)

        self.schedule_result = pd.DataFrame(schedule_list)

        # 检查安排完整性
        total_exams = len(self.students)
        scheduled_exams = len(self.schedule_result)
        arrangement_rate = scheduled_exams / total_exams * 100

        print(f"安排完成: {scheduled_exams}/{total_exams} 条考试记录已安排")
        print(f"安排率: {arrangement_rate:.2f}%")

        if scheduled_exams < total_exams:
            print(f"警告: 有 {total_exams - scheduled_exams} 条考试记录未能安排")
            # 尝试安排剩余的学生
            self._schedule_remaining_students(dates, schedule_list, classroom_usage, student_schedule)
            self.schedule_result = pd.DataFrame(schedule_list)
            scheduled_exams = len(self.schedule_result)
            arrangement_rate = scheduled_exams / total_exams * 100
            print(f"重新安排后: {scheduled_exams}/{total_exams} 条考试记录已安排")
            print(f"重新安排率: {arrangement_rate:.2f}%")

        return True

    def _schedule_student_group(self, student_group, exam_type, dates, schedule_list, classroom_usage,
                                student_schedule):
        """安排一组学生（开卷或闭卷）"""
        for student_id, student_info in student_group:
            if student_id in student_schedule:
                continue  # 学生已安排

            exam_count = student_info['exam_count']
            exams = student_info['exams']

            # 根据考试数量确定安排计划
            schedule_plan = self._get_student_schedule_plan(exam_count)

            # 尝试安排学生
            scheduled = self._schedule_student_with_plan(
                student_id, student_info, schedule_plan, exam_type,
                dates, schedule_list, classroom_usage, student_schedule
            )

            if not scheduled:
                print(f"无法安排学生: {student_info['name']} ({exam_count}门考试)")

    def _schedule_student_with_plan(self, student_id, student_info, schedule_plan, exam_type,
                                    dates, schedule_list, classroom_usage, student_schedule):
        """按照计划安排学生"""
        exam_count = student_info['exam_count']
        exams = student_info['exams']
        days_needed = schedule_plan['days']
        exams_per_day = schedule_plan['exams_per_day']
        flexible = schedule_plan.get('flexible', False)
        require_same_half_day = schedule_plan.get('require_same_half_day', False)

        # 尝试找到连续的日期来安排
        for start_date_idx in range(len(dates) - days_needed + 1):
            candidate_dates = dates[start_date_idx:start_date_idx + days_needed]

            # 检查这些日期是否都有足够的时间单元
            day_schedules = []
            for i, date in enumerate(candidate_dates):
                day_exam_count = exams_per_day[i]
                day_require_same_half_day = require_same_half_day and i == 0  # 只有第一天可能需要同半天

                available_slots = self._get_available_time_slots(
                    date, day_exam_count, day_require_same_half_day, flexible
                )

                if not available_slots:
                    break

                day_schedules.append((date, available_slots))

            if len(day_schedules) == days_needed:
                # 找到合适的日期组合，尝试安排
                if self._assign_student_to_dates(
                        student_id, student_info, day_schedules, exam_type,
                        schedule_list, classroom_usage
                ):
                    student_schedule[student_id] = {
                        'dates': [date for date, _ in day_schedules],
                        'exam_count': exam_count
                    }
                    return True

        return False

    def _assign_student_to_dates(self, student_id, student_info, day_schedules, exam_type,
                                 schedule_list, classroom_usage):
        """将学生安排到指定的日期"""
        exams = student_info['exams']
        exam_idx = 0

        for date, available_slots_list in day_schedules:
            # 为这一天选择一个时间单元组合
            slot_combination_found = False

            for slot_combination in available_slots_list:
                # 检查是否有足够的考场
                classroom_assignments = []
                can_assign = True

                for _, slot in slot_combination.iterrows():
                    available_classrooms = self._find_available_classroom_for_slot(
                        slot['时间单元编号*'], exam_type, classroom_usage
                    )

                    if not available_classrooms:
                        can_assign = False
                        break

                    # 选择第一个可用的考场
                    classroom = available_classrooms[0]
                    classroom_assignments.append((slot, classroom))

                if can_assign:
                    # 安排学生考试
                    for slot, classroom in classroom_assignments:
                        if exam_idx < len(exams):
                            exam = exams[exam_idx]

                            schedule_list.append({
                                '考生姓名*': exam['考生姓名*'],
                                '考生学号*': student_id,
                                '课程编号*': exam['课程编号*'],
                                '课程名称*': exam['课程名称*'],
                                '开闭卷': exam['开闭卷'],
                                '时间单元编号': slot['时间单元编号*'],
                                '考试开始时间': slot['考试开始时间*'],
                                '考场编号': classroom['考场编号'],
                                '考场名称': classroom['考场名称'],
                                '考试日期': date,
                                '考试顺序': exam_idx + 1
                            })

                            # 更新考场使用情况
                            classroom_usage[slot['时间单元编号*']][classroom['考场编号']] += 1
                            classroom_usage[slot['时间单元编号*']][f"{classroom['考场编号']}_type"] = exam['开闭卷']

                            exam_idx += 1

                    slot_combination_found = True
                    break

            if not slot_combination_found:
                return False

        return True

    def _schedule_remaining_students(self, dates, schedule_list, classroom_usage, student_schedule):
        """安排剩余的学生 - 使用更宽松的策略"""
        print("尝试安排剩余的学生...")

        # 获取所有未安排的学生
        all_students = set(self.student_exams.keys())
        scheduled_students = set(student_schedule.keys())
        remaining_students = all_students - scheduled_students

        print(f"剩余学生数量: {len(remaining_students)}")

        # 尝试安排剩余的学生
        for student_id in remaining_students:
            student_info = self.student_exams[student_id]
            exams = student_info['exams']

            # 尝试安排每门考试
            for exam_idx, exam in enumerate(exams):
                exam_type = exam['开闭卷']

                # 尝试所有日期和时间单元
                scheduled = False
                for date in dates:
                    if scheduled:
                        break

                    date_slots = self.time_slots[self.time_slots['考试日期'] == date]

                    for _, slot in date_slots.iterrows():
                        available_classrooms = self._find_available_classroom_for_slot(
                            slot['时间单元编号*'], exam_type, classroom_usage
                        )

                        if available_classrooms:
                            # 选择第一个可用的考场
                            classroom = available_classrooms[0]

                            schedule_list.append({
                                '考生姓名*': exam['考生姓名*'],
                                '考生学号*': student_id,
                                '课程编号*': exam['课程编号*'],
                                '课程名称*': exam['课程名称*'],
                                '开闭卷': exam['开闭卷'],
                                '时间单元编号': slot['时间单元编号*'],
                                '考试开始时间': slot['考试开始时间*'],
                                '考场编号': classroom['考场编号'],
                                '考场名称': classroom['考场名称'],
                                '考试日期': date,
                                '考试顺序': exam_idx + 1
                            })

                            # 更新考场使用情况
                            classroom_usage[slot['时间单元编号*']][classroom['考场编号']] += 1
                            classroom_usage[slot['时间单元编号*']][f"{classroom['考场编号']}_type"] = exam['开闭卷']

                            scheduled = True
                            break

    def save_schedule(self, filename):
        """保存安排结果"""
        if self.schedule_result is not None:
            self.schedule_result.to_excel(filename, index=False)
            return True
        return False

    def get_statistics(self):
        """获取统计信息"""
        if self.schedule_result is None:
            return None

        # 检查安排质量
        student_schedule_quality = self._check_student_schedule_quality()

        stats = {
            '总安排考试数': len(self.schedule_result),
            '安排学生数': self.schedule_result['考生学号*'].nunique(),
            '开卷考试数': len(self.schedule_result[self.schedule_result['开闭卷'] == '开卷']),
            '闭卷考试数': len(self.schedule_result[self.schedule_result['开闭卷'] == '闭卷']),
            '使用的考场数': self.schedule_result['考场编号'].nunique(),
            '使用的日期数': self.schedule_result['考试日期'].nunique(),
            '时间单元使用情况': self.schedule_result['时间单元编号'].value_counts().to_dict(),
            '安排质量': student_schedule_quality
        }

        # 计算安排率
        total_exams = len(self.students)
        scheduled_exams = len(self.schedule_result)
        stats['安排率'] = f"{scheduled_exams / total_exams * 100:.2f}%"

        return stats

    def _check_student_schedule_quality(self):
        """检查学生考试安排质量"""
        quality_stats = {
            '符合规则安排': 0,
            '不符合规则安排': 0,
            '考试1门任意安排': 0,
            '考试2门同半天': 0,
            '考试3-4门同一天': 0,
            '考试5门以上多天': 0
        }

        student_groups = self.schedule_result.groupby('考生学号*')

        for student_id, group in student_groups:
            exam_count = len(group)
            unique_dates = group['考试日期'].unique()

            if exam_count == 1:
                # 只有一门考试，任意安排都符合规则
                quality_stats['考试1门任意安排'] += 1
                quality_stats['符合规则安排'] += 1

            elif exam_count == 2:
                # 检查是否同半天
                if len(unique_dates) == 1:
                    # 检查是否同半天
                    date = unique_dates[0]
                    date_exams = group[group['考试日期'] == date]
                    time_orders = []

                    for _, exam in date_exams.iterrows():
                        time_slot_id = exam['时间单元编号']
                        time_order = int(time_slot_id.split('-')[-1])
                        time_orders.append(time_order)

                    # 检查是否同半天
                    has_morning = any(order in [1, 2] for order in time_orders)
                    has_afternoon = any(order in [3, 4] for order in time_orders)

                    if not (has_morning and has_afternoon):  # 不同时包含上午和下午
                        quality_stats['考试2门同半天'] += 1
                        quality_stats['符合规则安排'] += 1
                    else:
                        quality_stats['不符合规则安排'] += 1
                else:
                    quality_stats['不符合规则安排'] += 1

            elif exam_count <= 4:
                # 检查是否同一天
                if len(unique_dates) == 1:
                    quality_stats['考试3-4门同一天'] += 1
                    quality_stats['符合规则安排'] += 1
                else:
                    quality_stats['不符合规则安排'] += 1

            else:  # exam_count > 4
                # 检查是否最多两天
                if len(unique_dates) <= 2:
                    quality_stats['考试5门以上多天'] += 1
                    quality_stats['符合规则安排'] += 1
                else:
                    quality_stats['不符合规则安排'] += 1

        return quality_stats


class ExamSchedulerGUI:
    def __init__(self, root):
        self.root = root
        self.root.title("智能考试安排系统 - 灵活版")
        self.root.geometry("1200x800")

        self.scheduler = ExamScheduler()

        self.setup_ui()

    def setup_ui(self):
        """设置用户界面"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))

        # 文件选择区域
        file_frame = ttk.LabelFrame(main_frame, text="数据文件", padding="10")
        file_frame.grid(row=0, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)

        # 考场文件
        ttk.Label(file_frame, text="考场信息表:").grid(row=0, column=0, sticky=tk.W)
        self.classroom_file = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.classroom_file, width=60).grid(row=0, column=1, padx=5)
        ttk.Button(file_frame, text="选择", command=self.select_classroom_file).grid(row=0, column=2)

        # 时间文件
        ttk.Label(file_frame, text="考试时间单元:").grid(row=1, column=0, sticky=tk.W, pady=5)
        self.timeslot_file = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.timeslot_file, width=60).grid(row=1, column=1, padx=5)
        ttk.Button(file_frame, text="选择", command=self.select_timeslot_file).grid(row=1, column=2)

        # 学生文件
        ttk.Label(file_frame, text="学生数据:").grid(row=2, column=0, sticky=tk.W)
        self.student_file = tk.StringVar()
        ttk.Entry(file_frame, textvariable=self.student_file, width=60).grid(row=2, column=1, padx=5)
        ttk.Button(file_frame, text="选择", command=self.select_student_file).grid(row=2, column=2)

        # 按钮区域
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=1, column=0, columnspan=2, pady=10)

        ttk.Button(button_frame, text="加载数据", command=self.load_data).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="生成安排", command=self.generate_schedule).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="保存结果", command=self.save_result).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="显示统计", command=self.show_statistics).pack(side=tk.LEFT, padx=5)
        ttk.Button(button_frame, text="检查安排质量", command=self.check_schedule_quality).pack(side=tk.LEFT, padx=5)

        # 结果显示区域
        result_frame = ttk.LabelFrame(main_frame, text="安排结果", padding="10")
        result_frame.grid(row=2, column=0, columnspan=2, sticky=(tk.W, tk.E, tk.N, tk.S), pady=5)

        # 创建树形视图显示结果
        columns = ('考生姓名', '学号', '课程', '开闭卷', '时间单元', '考场', '日期', '考试顺序')
        self.tree = ttk.Treeview(result_frame, columns=columns, show='headings', height=15)

        # 设置列标题
        for col in columns:
            self.tree.heading(col, text=col)
            if col in ['考生姓名', '课程', '考场']:
                self.tree.column(col, width=150)
            else:
                self.tree.column(col, width=100)

        # 滚动条
        scrollbar = ttk.Scrollbar(result_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscroll=scrollbar.set)

        self.tree.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar.grid(row=0, column=1, sticky=(tk.N, tk.S))

        # 统计信息区域
        stats_frame = ttk.LabelFrame(main_frame, text="统计信息", padding="10")
        stats_frame.grid(row=3, column=0, columnspan=2, sticky=(tk.W, tk.E), pady=5)

        self.stats_text = tk.Text(stats_frame, height=10, width=100)
        scrollbar_stats = ttk.Scrollbar(stats_frame, orient=tk.VERTICAL, command=self.stats_text.yview)
        self.stats_text.configure(yscrollcommand=scrollbar_stats.set)

        self.stats_text.grid(row=0, column=0, sticky=(tk.W, tk.E, tk.N, tk.S))
        scrollbar_stats.grid(row=0, column=1, sticky=(tk.N, tk.S))

        # 配置网格权重
        self.root.columnconfigure(0, weight=1)
        self.root.rowconfigure(0, weight=1)
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(2, weight=1)
        result_frame.columnconfigure(0, weight=1)
        result_frame.rowconfigure(0, weight=1)
        stats_frame.columnconfigure(0, weight=1)
        stats_frame.rowconfigure(0, weight=1)

    def select_classroom_file(self):
        filename = filedialog.askopenfilename(title="选择考场信息表", filetypes=[("Excel files", "*.xlsx")])
        if filename:
            self.classroom_file.set(filename)

    def select_timeslot_file(self):
        filename = filedialog.askopenfilename(title="选择考试时间单元", filetypes=[("Excel files", "*.xlsx")])
        if filename:
            self.timeslot_file.set(filename)

    def select_student_file(self):
        filename = filedialog.askopenfilename(title="选择学生数据", filetypes=[("Excel files", "*.xlsx")])
        if filename:
            self.student_file.set(filename)

    def load_data(self):
        if not all([self.classroom_file.get(), self.timeslot_file.get(), self.student_file.get()]):
            messagebox.showerror("错误", "请选择所有数据文件")
            return

        if self.scheduler.load_data(self.classroom_file.get(), self.timeslot_file.get(), self.student_file.get()):
            messagebox.showinfo("成功", "数据加载成功")
        else:
            messagebox.showerror("错误", "数据加载失败")

    def generate_schedule(self):
        if self.scheduler.classrooms is None:
            messagebox.showerror("错误", "请先加载数据")
            return

        # 显示进度
        progress_window = tk.Toplevel(self.root)
        progress_window.title("安排进度")
        progress_window.geometry("300x100")
        progress_label = ttk.Label(progress_window, text="正在生成考试安排，请稍候...")
        progress_label.pack(pady=20)
        progress_window.update()

        if self.scheduler.generate_schedule():
            # 清空现有显示
            for item in self.tree.get_children():
                self.tree.delete(item)

            # 显示前200条记录
            display_data = self.scheduler.schedule_result.head(200)
            for _, row in display_data.iterrows():
                self.tree.insert('', tk.END, values=(
                    row['考生姓名*'],
                    row['考生学号*'],
                    row['课程名称*'],
                    row['开闭卷'],
                    row['时间单元编号'],
                    row['考场名称'],
                    row['考试日期'],
                    row.get('考试顺序', 1)
                ))

            progress_window.destroy()
            total_exams = len(self.scheduler.students)
            scheduled_exams = len(self.scheduler.schedule_result)
            arrangement_rate = scheduled_exams / total_exams * 100
            messagebox.showinfo("成功",
                                f"考试安排生成完成！\n"
                                f"共安排 {scheduled_exams}/{total_exams} 条考试记录\n"
                                f"安排率: {arrangement_rate:.2f}%")
        else:
            progress_window.destroy()
            messagebox.showerror("错误", "考试安排生成失败")

    def save_result(self):
        if self.scheduler.schedule_result is None:
            messagebox.showerror("错误", "没有可保存的安排结果")
            return

        filename = filedialog.asksaveasfilename(
            title="保存安排结果",
            defaultextension=".xlsx",
            filetypes=[("Excel files", "*.xlsx")]
        )

        if filename:
            if self.scheduler.save_schedule(filename):
                messagebox.showinfo("成功", f"安排结果已保存到: {filename}")
            else:
                messagebox.showerror("错误", "保存失败")

    def show_statistics(self):
        if self.scheduler.schedule_result is None:
            messagebox.showerror("错误", "没有可显示的统计信息")
            return

        stats = self.scheduler.get_statistics()
        if stats:
            self.stats_text.delete(1.0, tk.END)
            stats_text = f"考试安排统计信息:\n{'=' * 50}\n\n"
            stats_text += f"总安排考试数: {stats['总安排考试数']}\n"
            stats_text += f"安排学生数: {stats['安排学生数']}\n"
            stats_text += f"开卷考试数: {stats['开卷考试数']}\n"
            stats_text += f"闭卷考试数: {stats['闭卷考试数']}\n"
            stats_text += f"使用的考场数: {stats['使用的考场数']}\n"
            stats_text += f"使用的日期数: {stats['使用的日期数']}\n"
            stats_text += f"安排率: {stats['安排率']}\n\n"

            stats_text += f"安排质量分析:\n"
            stats_text += f"  符合规则安排: {stats['安排质量']['符合规则安排']} 人\n"
            stats_text += f"  不符合规则安排: {stats['安排质量']['不符合规则安排']} 人\n"
            stats_text += f"  考试1门任意安排: {stats['安排质量']['考试1门任意安排']} 人\n"
            stats_text += f"  考试2门同半天: {stats['安排质量']['考试2门同半天']} 人\n"
            stats_text += f"  考试3-4门同一天: {stats['安排质量']['考试3-4门同一天']} 人\n"
            stats_text += f"  考试5门以上多天: {stats['安排质量']['考试5门以上多天']} 人\n\n"

            stats_text += "时间单元使用情况:\n"
            for slot, count in stats['时间单元使用情况'].items():
                stats_text += f"  {slot}: {count} 场考试\n"

            self.stats_text.insert(1.0, stats_text)

    def check_schedule_quality(self):
        """检查考试安排质量"""
        if self.scheduler.schedule_result is None:
            messagebox.showerror("错误", "没有安排结果可检查")
            return

        # 分析学生考试安排质量
        student_quality_analysis = {}
        student_groups = self.scheduler.schedule_result.groupby('考生学号*')

        for student_id, group in student_groups:
            student_name = group.iloc[0]['考生姓名*']
            exam_count = len(group)
            unique_dates = group['考试日期'].unique()

            if exam_count == 1:
                expected = "任意安排"
                status = "符合规则"  # 单门考试任意安排都符合规则

            elif exam_count == 2:
                expected = "同半天"
                if len(unique_dates) == 1:
                    # 检查是否同半天
                    date = unique_dates[0]
                    date_exams = group[group['考试日期'] == date]
                    time_orders = []

                    for _, exam in date_exams.iterrows():
                        time_slot_id = exam['时间单元编号']
                        time_order = int(time_slot_id.split('-')[-1])
                        time_orders.append(time_order)

                    # 检查是否同半天
                    has_morning = any(order in [1, 2] for order in time_orders)
                    has_afternoon = any(order in [3, 4] for order in time_orders)

                    if not (has_morning and has_afternoon):  # 不同时包含上午和下午
                        status = "符合规则"
                    else:
                        status = "不符合规则"
                else:
                    status = "不符合规则"

            elif exam_count <= 4:
                expected = "同一天"
                if len(unique_dates) == 1:
                    status = "符合规则"
                else:
                    status = "不符合规则"

            else:  # exam_count > 4
                expected = "最多两天"
                if len(unique_dates) <= 2:
                    status = "符合规则"
                else:
                    status = "不符合规则"

            student_quality_analysis[student_id] = {
                'name': student_name,
                'exam_count': exam_count,
                'expected': expected,
                'status': status,
                'actual_dates': len(unique_dates)
            }

        # 显示质量检查结果
        quality_window = tk.Toplevel(self.root)
        quality_window.title("考试安排质量检查")
        quality_window.geometry("800x600")

        # 创建树形视图显示质量结果
        columns = ('学号', '姓名', '考试数量', '期望安排', '状态', '实际天数')
        tree = ttk.Treeview(quality_window, columns=columns, show='headings', height=25)

        for col in columns:
            tree.heading(col, text=col)
            tree.column(col, width=120)

        # 填充数据
        for student_id, analysis in student_quality_analysis.items():
            tree.insert('', tk.END, values=(
                student_id,
                analysis['name'],
                analysis['exam_count'],
                analysis['expected'],
                analysis['status'],
                analysis['actual_dates']
            ))

        tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

        # 统计各种状态的数量
        status_count = {}
        for analysis in student_quality_analysis.values():
            status = analysis['status']
            status_count[status] = status_count.get(status, 0) + 1

        status_text = "\n".join([f"{status}: {count} 人" for status, count in status_count.items()])
        messagebox.showinfo("质量统计", f"考试安排质量统计:\n\n{status_text}")


def main():
    root = tk.Tk()
    app = ExamSchedulerGUI(root)
    root.mainloop()


if __name__ == "__main__":
    main()